package com.ali.sso.common.shiro.realm;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;

/**
 * 应用身份(登陆用户)认证过滤器
 * @author cwang
 */
public class AppAuthenticatingFilter extends AuthenticatingFilter {
	static Log logger = LogFactory.getLog(AppAuthenticatingFilter.class);
	
    //oauth2 authc code参数名
    private String authcCodeParam = "code";
    //客户端id
    private String clientId;
    //服务器端登录成功
    private String redirectUrl;
    //oauth2服务器响应类型
    private String responseType = "code";
    //失败后重定向到的客户端地址
    private String failureUrl;
    
	@Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpRequest = (HttpServletRequest)request;
        String code = httpRequest.getParameter(authcCodeParam);
        logger.info("createToken : code=" + code);
        return new AppAuthenticationToken(code);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        String error = request.getParameter("error");
        String errorDescription = request.getParameter("error_description");
        
        //如果SSO返回了错误，则重定向到SSO的统一错误页面
        if(!StringUtils.isEmpty(error)) {
        	logger.error("error:" + error + ", error_description:" + errorDescription);
            WebUtils.issueRedirect(request, response, failureUrl + "?error=" + error + "error_description=" + errorDescription);
            return false;
        }

        Subject subject = getSubject(request, response);
        //如果用户没有身份验证，且没有auth code，则重定向到SSO授权
        if(!subject.isAuthenticated() && StringUtils.isEmpty(request.getParameter(authcCodeParam))) {
            saveRequestAndRedirectToLogin(request, response);
            return false;
        }
        /*if(!subject.isAuthenticated()) {
            if(StringUtils.isEmpty(request.getParameter(authcCodeParam))) {
                //如果用户没有身份验证，且没有auth code，则重定向到服务端授权
                saveRequestAndRedirectToLogin(request, response);
                return false;
            }
        }*/

        return executeLogin(request, response);
    }

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
    	logger.info("onLoginSuccess...");
    	issueSuccessRedirect(request, response);
        return false;
    }

    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException ae, ServletRequest request, ServletResponse response) {
        Subject subject = getSubject(request, response);
        if (subject.isAuthenticated() || subject.isRemembered()) {
            try {
            	logger.info("onLoginSuccess...");
                issueSuccessRedirect(request, response);
            } catch (Exception e) {
            	logger.error(e);
            }
        } else {
            try {
            	logger.info("onLoginFailure...");
                WebUtils.issueRedirect(request, response, failureUrl);
            } catch (IOException e) {
            	logger.error(e);
            }
        }
        return false;
    }
    
	@Override
	protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
		return super.preHandle(request, response);
	}
    
	public void setAuthcCodeParam(String authcCodeParam) {
		this.authcCodeParam = authcCodeParam;
	}
	public void setClientId(String clientId) {
		this.clientId = clientId;
	}
	public void setRedirectUrl(String redirectUrl) {
		this.redirectUrl = redirectUrl;
	}
	public void setResponseType(String responseType) {
		this.responseType = responseType;
	}
	public void setFailureUrl(String failureUrl) {
		this.failureUrl = failureUrl;
	}

}
